package rss.services 
{
	import flash.events.IEventDispatcher;
	import rss.builder.XmlRssFeedBuilder;
	import rss.events.RssFeedEvent;
	import rss.IRssFeedBuilder;
	import rss.IRssFeedModel;
	import rss.IRssService;
	import rss.models.RssFeedModel;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	///
	[Event(name = "ioError", type = "flash.events.IOErrorEvent")]
	
	///
	[Event(name = "securityError", type = "flash.events.SecurityErrorEvent")] 
	
	///
	[Event(name = "progress", type = "flash.events.ProgressEvent")] 
	
	///
	[Event(name = "loaded", type = "rss.events.RssFeedEvent")]

	
	/**
	 * TODO: document
	 * 
	 * @author Luke Van In
	 */
	public class RssService implements IRssService 
	{
		
		private var _eventDispatcher:IEventDispatcher;
		
		private var _loader:URLLoader;
		
		
		
		public function RssService(eventDispatcher:IEventDispatcher) 
		{
			this._eventDispatcher = eventDispatcher;
		}
		
		
		
		/* INTERFACE rss.IRssService */
		
		/**
		 * 
		 * @param	url
		 */
		public function loadFeed(url:String):void 
		{
			trace("RssService > loadFeed: " + url);
			
			// dispose existing loader
			if (this._loader != null)
				this.disposeLoader(this._loader);
				
			// create loader to fetch data
			this._loader = this.createLoader();
			
			// create request and fetch data
			var request:URLRequest = new URLRequest(url);
			
			this._loader.load(request);
		}
		
		
		
		
		/**
		 * Creates and assigns event listeners to an instance of a URLLoader object
		 * @return
		 */
		private function createLoader():URLLoader
		{
			var loader:URLLoader = new URLLoader();
			
			loader.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
			
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
			
			loader.addEventListener(ProgressEvent.PROGRESS, this.progressHandler);
			
			loader.addEventListener(Event.COMPLETE, this.completeHandler);
			
			return loader;
		}
		
		
		
		/**
		 * 
		 * @param	loader
		 */
		private function disposeLoader(loader:URLLoader):void
		{
			if (loader == null)
				return;
				
			loader.removeEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
			
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
			
			loader.removeEventListener(ProgressEvent.PROGRESS, this.progressHandler);
			
			loader.removeEventListener(Event.COMPLETE, this.completeHandler);	
			
			try
			{
				loader.close();
			}
			catch (e:Error)
			{
				// leader was not open
			}
		}
		
		
		
		/**
		 * Called when an IO error occurs (such as when no network connection is available)
		 * 
		 * @param	e
		 */
		private function ioErrorHandler(e:IOErrorEvent):void 
		{
			this._eventDispatcher.dispatchEvent(e);
		}
		
		
		
		/**
		 * Called when a security error occurs (such as when a crossdomain policy file is missing, or is present but prevents access to the requested resource) 
		 * 
		 * @param	e
		 */
		private function securityErrorHandler(e:SecurityErrorEvent):void 
		{
			this._eventDispatcher.dispatchEvent(e);
		}
		
		
		
		/**
		 * Called when a quantity of data is fetched from the requested resource
		 * 
		 * @param	e
		 */
		private function progressHandler(e:ProgressEvent):void
		{
			this._eventDispatcher.dispatchEvent(e);
		}
		
		
		
		/**
		 * Called when the data has completed downloading
		 * 
		 * @param	e
		 */
		private function completeHandler(e:Event):void
		{
			trace("RssService > completeHandler: " + this._loader.data);
			
			
			// get XML data from loader
			var data:String = this._loader.data as String;
			
			var xml:XML = new XML(data);
			
		
			// build the feed from the XML
			var feedBuilder:IRssFeedBuilder = new XmlRssFeedBuilder(xml);

			var feed:IRssFeedModel = feedBuilder.buildFeed();
			

			// dispose resources
			this.disposeLoader(this._loader);
			
			feedBuilder.dispose();
			
			
			// create and dispatch the event
			var event:RssFeedEvent = new RssFeedEvent(RssFeedEvent.LOADED, feed);
			
			this._eventDispatcher.dispatchEvent(event);
		}
		
		
		
		
		/**
		 * 
		 */ 
		public function dispose():void
		{
			this.disposeLoader(this._loader);
			
			this._loader = null;
		}

		
	}

}